﻿using System;
using System.IO;
using System.Text;

namespace RanbuOM.Serialization
{
    public class BinaryWriterEx : IDisposable
    {
        private readonly BinaryWriter writer;

        public Endianness Endianness { get; private set; }

        public BinaryWriterEx(Stream stream, Encoding encoding = null, Endianness endianness = Endianness.LittleEndian)
        {
            if (encoding == null)
            {
                encoding = Encoding.Default;
            }

            this.writer = new BinaryWriter(stream, encoding);
            this.Endianness = endianness;
        }

        public void WriteU8(byte value)
        {
            this.writer.Write(value);
        }

        public void WriteI8(sbyte value)
        {
            this.writer.Write(value);
        }

        public void WriteU16(ushort value)
        {
            var bytes = BitConverter.GetBytes(value);
            this.WriteEndiannessEffectiveBytes(bytes);
        }

        public void WriteI16(short value)
        {
            var bytes = BitConverter.GetBytes(value);
            this.WriteEndiannessEffectiveBytes(bytes);
        }

        public void WriteU32(uint value)
        {
            var bytes = BitConverter.GetBytes(value);
            this.WriteEndiannessEffectiveBytes(bytes);
        }

        public void WriteI32(int value)
        {
            var bytes = BitConverter.GetBytes(value);
            this.WriteEndiannessEffectiveBytes(bytes);
        }

        public void WriteU64(ulong value)
        {
            var bytes = BitConverter.GetBytes(value);
            this.WriteEndiannessEffectiveBytes(bytes);
        }

        public void WriteI64(long value)
        {
            var bytes = BitConverter.GetBytes(value);
            this.WriteEndiannessEffectiveBytes(bytes);
        }

        public void WriteR4(float value)
        {
            var bytes = BitConverter.GetBytes(value);
            this.WriteEndiannessEffectiveBytes(bytes);
        }

        public void WriteR8(double value)
        {
            var bytes = BitConverter.GetBytes(value);
            this.WriteEndiannessEffectiveBytes(bytes);
        }

        public void WriteCString(string value)
        {
            var chars = value.ToCharArray();
            this.writer.Write(chars);
            this.WriteU8(0);
        }

        public void WriteCharArrayString(string value, int count)
        {
            var chars = new char[count];
            var str = value.ToCharArray();
            Array.Copy(str, chars, Math.Min(count, str.Length));
            this.writer.Write(chars);
        }

        public void WriteChar(char value)
        {
            this.writer.Write(value);
        }

        public void WriteBytes(byte[] bytes)
        {
            this.writer.Write(bytes);
        }

        public void Seek(long offset, SeekOrigin seekOrigin = SeekOrigin.Begin)
        {
            this.writer.BaseStream.Seek(offset, seekOrigin);
        }

        public long Position
        {
            get { return this.writer.BaseStream.Position; }
        }

        public long Length
        {
            get { return this.writer.BaseStream.Length; }
        }

        public void Close()
        {
            this.writer.Close();
        }

        public void Dispose()
        {
            this.writer.Dispose();
        }

        private void WriteEndiannessEffectiveBytes(byte[] bytes)
        {
            if (this.Endianness != Endianness.LittleEndian)
            {
                Array.Reverse(bytes);
            }

            this.writer.Write(bytes);
        }
    }
}
